﻿#region 命名空间

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using AutoMapper;
using Sharp.DataTransferObject;
using Sharp.Domain.PlatformBoundedContext.PermissionModule.Aggregates;
using Sharp.Domain.PlatformBoundedContext.UserModule.Aggregates;
using Sharp.Domain.Repositories;
using Sharp.Infrastructure;
using Sharp.Infrastructure.Crosscutting;
using Sharp.Infrastructure.Search;

#endregion

namespace Sharp.Application.Platform
{
    /// <summary>
    ///     用户服务
    /// </summary>
    public class UserServiceImpl : ApplicationService, Sharp.ServiceContracts.IUserService
    {
        #region 私有字段

        private readonly Sharp.Domain.PlatformBoundedContext.UserModule.Services.IUserService _domainService;
        private readonly IPermissionRepository _permissionRepository;
        private readonly IRoleRepository _roleRepository;
        private readonly IUserGroupRepository _userGroupRepository;
        private readonly IUserRepository _userRepository;
        private readonly IUserLogRepository _userLogRepository;
        #endregion

        #region 构造函数

        /// <summary>
        ///     初始化一个新的<c>UserServiceImpl</c>实例。
        /// </summary>
        /// <param name="context"></param>
        /// <param name="userRepository"></param>
        /// <param name="roleRepository"></param>
        /// <param name="userGroupRepository"></param>
        /// <param name="permissionRepository"></param>
        /// <param name="userLogRepository"></param>
        /// <param name="domainService"></param>
        public UserServiceImpl(IRepositoryContext context,
            IUserRepository userRepository,
            IRoleRepository roleRepository,
            IUserGroupRepository userGroupRepository,
            IPermissionRepository permissionRepository,
            IUserLogRepository userLogRepository,
            Sharp.Domain.PlatformBoundedContext.UserModule.Services.IUserService domainService)
            : base(context)
        {
            _userRepository = userRepository;
            _roleRepository = roleRepository;
            _userGroupRepository = userGroupRepository;
            _permissionRepository = permissionRepository;
            _userLogRepository = userLogRepository;
            _domainService = domainService;
        }

        #endregion

        #region 新增用户
        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="userDTO">包含了客户信息的数据传输对象。</param>
        /// <returns>已创建客户对象的全局唯一标识。</returns>
        public Result CreateUser(UserDTO userDTO)
        {
            if (userDTO == null)
                throw new ArgumentNullException(nameof(userDTO));

            var res = new Result();
            var user = userDTO.To<User>();
            user.Profile.RegisteredTime = DateTime.Now;

            _userRepository.Add(user);
            Context.Commit();

            return res;
        }
        #endregion

        #region 新增用户

        /// <summary>
        /// 新增用户
        /// </summary>
        /// <param name="userdto">包含了客户信息的数据传输对象。</param>
        /// <returns>已创建客户对象的全局唯一标识。</returns>
        [Logging("保存用户，{@p0.UserName}")]
        public Result SaveUser(UserDTO userdto)
        {
            if (userdto == null)
                throw new ArgumentNullException("userdto");

            var res = new Result();

            if (userdto.Id.IsEmpty())
            {
                var user = userdto.To<User>();
                user.RegisteredTime = DateTime.Now;
                user.LastPasswordChangedDate = DateTime.Parse("1900-1-1");
                if (userdto.UserGroupIds != null)
                {
                    user.UserGroups = _userGroupRepository.GetList(x => userdto.UserGroupIds.Contains(x.Id));
                }
                _userRepository.Add(user);
            }
            else
            {
                var persisted = _userRepository.Get(userdto.Id, x => x.UserGroups);
                persisted.Comment = userdto.Comment;
                persisted.Email = userdto.Email;
                if (!userdto.Password.IsNullOrEmpty())
                {
                    persisted.Password = userdto.Password.Sha1();
                }


                persisted.UserGroups.Clear();

                //var ugIds = userdto.UserGroupIds;
                if (userdto.UserGroupIds != null)
                    persisted.UserGroups = _userGroupRepository.GetList(x => userdto.UserGroupIds.Contains(x.Id));
            }

            Context.Commit();

            return res;
        }

        #endregion

        #region 校验指定的客户用户名与密码是否一致。
        /// <summary>
        ///     校验指定的客户用户名与密码是否一致。
        /// </summary>
        /// <param name="userName">客户用户名。</param>
        /// <param name="password">客户密码。</param>
        /// <returns>如果校验成功，则返回true，否则返回false。</returns>
        public bool ValidateUser(string userName, string password)
        {
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentNullException(nameof(userName));
            if (string.IsNullOrEmpty(password))
                throw new ArgumentNullException(nameof(password));

            return _domainService.CheckPassword(userName, password.Md5());
        }
        #endregion

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="userDTO"></param>
        /// <returns></returns>
        public Result<UserDTO> TryLogin(UserDTO userDTO)
        {
            User user = userDTO.To<User>();
            user.LoginWhichSystem(userDTO.SystemCode);

            var res = _domainService.TryLogin(user);


            Result<UserDTO> output = new Result<UserDTO>();
            output.Err = res.Err;
            output.Data = res.Data.To<UserDTO>();

            return output;
        }

        /// <summary>
        ///     禁用指定用户。
        /// </summary>
        /// <param name="user">需要禁用的用户。</param>
        /// <returns>如果成功，则返回true，否则返回false。</returns>
        public bool DisableUser(UserDTO user)
        {
            if (user == null)
                throw new ArgumentNullException(nameof(user));
            User userinfo = null;
            if (user.Id != Guid.Empty)
                userinfo = _userRepository.Get(user.Id, x => x.Profile);
            else if (!string.IsNullOrEmpty(user.UserName))
                userinfo = _domainService.GetUserByName(user.UserName);
            else if (!string.IsNullOrEmpty(user.Email))
                userinfo = _domainService.GetUserByEmail(user.Email);
            else
                throw new ArgumentNullException(nameof(user), "未赋值");
            userinfo.Profile.IsLockedOut = true;
            _userRepository.Update(userinfo);
            Context.Commit();

            return true;
        }

        /// <summary>
        ///     启用指定用户。
        /// </summary>
        /// <param name="userdto">需要启用的用户。</param>
        /// <returns>如果成功，则返回true，否则返回false。</returns>
        public bool EnableUser(UserDTO userdto)
        {
            if (userdto == null)
                throw new ArgumentNullException("userdto");
            User user = null;
            if (userdto.Id != Guid.Empty)
                user = _userRepository.Get(userdto.Id, x => x.Profile);
            else if (!string.IsNullOrEmpty(userdto.UserName))
                user = _domainService.GetUserByName(userdto.UserName);
            else if (!string.IsNullOrEmpty(userdto.Email))
                user = _domainService.GetUserByEmail(userdto.Email);
            else
                throw new ArgumentNullException("userdto", "未赋值");
            user.Profile.IsLockedOut = false;
            _userRepository.Update(user);
            Context.Commit();

            return true;
        }

        /// <summary>
        ///     根据指定的用户信息，更新用户对象。
        /// </summary>
        /// <param name="userdto">需要更新的用户对象。</param>
        /// <returns>已更新的用户对象。</returns>
        public Result UpdateUser(UserDTO userdto)
        {
            var res = new Result();

            var persisted = _userRepository.Get(userdto.Id, x => x.Profile);

            persisted.Profile.Comment = userdto.Comment;
            persisted.Email = userdto.Email;
            if (!userdto.Password.IsNullOrEmpty())
            {
                persisted.Password = userdto.Password.Md5();
            }
            persisted.Profile.PasswordQuestion = userdto.PasswordQuestion;

            Context.Committed = false;
            Context.Commit();
            return res;
        }

        /// <summary>
        ///     删除用户。
        /// </summary>
        /// <param name="userids">需要删除的用户的Id。</param>
        public Result DeleteUsers(IList<Guid> userids)
        {
            var res = new Result();
            if (userids == null)
            {
                res.Err = "参数不可为空。";
                return res;
            }

            _userRepository.Remove(userids);

            Context.Commit();

            return res;
        }

        /// <summary>
        ///     根据用户的全局唯一标识获取用户信息。
        /// </summary>
        /// <param name="id">用户的全局唯一标识。</param>
        /// <returns>包含了用户信息的数据传输对象。</returns>
        public Result<UserDTO> GetUserByKey(Guid id)
        {
            var user = _userRepository.Get(id);
            var res = new Result<UserDTO>(user.To<UserDTO>());

            return res;
        }

        /// <summary>
        ///     根据用户的电子邮件地址获取用户信息。
        /// </summary>
        /// <param name="email">用户的电子邮件地址。</param>
        /// <returns>包含了用户信息的数据传输对象。</returns>
        public Result<UserDTO> GetUserByEmail(string email)
        {
            if (string.IsNullOrEmpty(email))
                throw new ArgumentException("email");
            var user = _domainService.GetUserByEmail(email);

            var res = new Result<UserDTO>(user.To<UserDTO>());
            return res;
        }

        /// <summary>
        ///     根据用户的用户名获取用户信息。
        /// </summary>
        /// <param name="userName">用户的用户名。</param>
        /// <returns>包含了用户信息的数据传输对象。</returns>
        public Result<UserDTO> GetUserByName(string userName)
        {
            if (string.IsNullOrEmpty(userName))
                throw new ArgumentException("userName");
            var user = _domainService.GetUserByName(userName);

            var res = new Result<UserDTO>(user.To<UserDTO>());
            return res;
        }
        /// <summary>
        /// 关联用户
        /// </summary>
        /// <param name="userGroupId">用户组Id</param>
        /// <param name="userIds">用户Id</param>
        /// <returns></returns>
        public Result RelationUser(Guid userGroupId, Guid[] userIds)
        {
            if (userIds == null)
            {
                return new Result() { Err = "用户Id参数不能为空。" };
            }
            var res = _domainService.RelationUser(userGroupId, userIds);

            Context.Commit();
            return res;
        }

        /// <summary>
        /// 反关联用户
        /// </summary>
        /// <param name="userGroupId">用户组Id</param>
        /// <param name="userIds">用户Id</param>
        /// <returns></returns>
        public Result UnRelationUser(Guid userGroupId, Guid[] userIds)
        {
            if (userIds == null)
            {
                return new Result() { Err = "用户Id参数不能为空。" };
            }
            var res = _domainService.UnRelationUser(userGroupId, userIds);

            Context.Commit();
            return res;
        }

        /// <summary>
        /// 获取UserGroup分页数据
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public PagedResult<UserGroupDTO> GetUserGroupPaged(PagingFeature pf)
        {
            var paged = _userGroupRepository.Pagging(pf);

            return paged.To<UserGroup, UserGroupDTO>();
        }

        /// <summary>
        ///     根据用户组的唯一ID，得到用户组传输对象
        /// </summary>
        /// <param name="id">用户组唯一标识</param>
        /// <returns></returns>
        public UserGroupDTO GetUserGroupByKey(Guid id)
        {
            var usergroup = _userGroupRepository.Get(id);
            var userGroupDto = usergroup.To<UserGroupDTO>();

            return userGroupDto;
        }

        /// <summary>
        ///     新增用户组
        /// </summary>
        /// <param name="userGroupDto">用户组对象</param>
        public void CreateUserGroup(UserGroupDTO userGroupDto)
        {
            if (userGroupDto == null)
                throw new ArgumentNullException("userGroupDto");

            var usergroup = userGroupDto.To<UserGroup>();


            _userGroupRepository.Add(usergroup);

            Context.Commit();
        }

        /// <summary>
        ///     更新用户组传输对象
        /// </summary>
        /// <param name="userGroupDto">用户组对象</param>
        /// <returns>用户组对象结果集</returns>
        public Result UpdateUserGroup(UserGroupDTO userGroupDto)
        {
            var res = new Result();

            var persisted = _userGroupRepository.Get(userGroupDto.Id);

            persisted.ModifiTime = DateTime.Now;
            persisted.Remark = userGroupDto.Remark;
            persisted.Title = userGroupDto.Title;

            _userGroupRepository.Update(persisted);
            Context.Commit();
            return res;

        }

        /// <summary>
        ///     更新用户组传输对象
        /// </summary>
        /// <param name="userGroupDto">用户组对象</param>
        /// <returns>用户组对象结果集</returns>
        [Logging("保存用户组，{@p0.Title}")]
        public Result SaveUserGroup(UserGroupDTO userGroupDto)
        {
            var res = new Result();
            if (userGroupDto.Id.IsEmpty())
            {
                var usergroup = userGroupDto.To<UserGroup>();


                _userGroupRepository.Add(usergroup);
            }
            else
            {
                var persisted = _userGroupRepository.Get(userGroupDto.Id);

                persisted.ModifiTime = DateTime.Now;
                persisted.Remark = userGroupDto.Remark;
                persisted.Title = userGroupDto.Title;

                _userGroupRepository.Update(persisted);
            }
            Context.Commit();
            return res;

        }
        /// <summary>
        ///     删除用户组(多条)
        /// </summary>
        /// <param name="userGroupids">用户组ID(多条)</param>
        /// <returns>用户组结果集</returns>
        public Result DeleteUserGroups(IList<Guid> userGroupids)
        {
            var res = new Result();
            if (userGroupids == null)
            {
                res.Err = "用户组Id参数不可为空！";
                return res;
            }

            _userGroupRepository.Remove(userGroupids);

            Context.Commit();

            return res;
        }
        /// <summary>
        /// 获取所有用户组
        /// </summary>
        /// <returns></returns>
        public Result<IEnumerable<UserGroupDTO>> GetUserGroups()
        {
            var res = new Result<IEnumerable<UserGroupDTO>>();

            res.Data = _userGroupRepository.GetList().To<UserGroup, UserGroupDTO>();

            return res;
        }

        ////////////////////////////////////////////////////////////
        /// UserGroup实现类 结束
        /// <summary>
        ///     根据指定的ID值，获取角色。
        /// </summary>
        /// <param name="id">指定的角色ID值。</param>
        /// <returns>角色。</returns>
        public RoleDTO GetRoleByKey(Guid id)
        {
            return Mapper.Map<Role, RoleDTO>(_roleRepository.Get(id));
        }

        /// <summary>
        ///     获取所有角色。
        /// </summary>
        /// <returns>所有角色。</returns>
        public IList<RoleDTO> GetRoles()
        {
            var roles = _roleRepository.GetList();
            IList<RoleDTO> result = null;
            if (roles != null &&
                roles.Any())
            {
                result = new List<RoleDTO>();
                roles.ToList()
                    .ForEach(r => result.Add(Mapper.Map<Role, RoleDTO>(r)));
            }
            return result;
        }

        /// <summary>
        ///     创建角色。
        /// </summary>
        /// <param name="roleDTO">需要创建的角色。</param>
        /// <returns>已创建的角色。</returns>
        public Result CreateRoles(RoleDTO roleDTO)
        {
            var res = new Result();

            // PerformCreateObjects(_roleRepository, roleDTO);
            return null;
            return res;
        }

        /// <summary>
        ///     更新角色。
        /// </summary>
        /// <param name="roleDTOs">需要更新的角色。</param>
        /// <returns>已更新的角色。</returns>
        public IList<RoleDTO> UpdateRoles(IList<RoleDTO> roleDTOs)
        {
            return null;
            //return PerformUpdateObjects<List<RoleDTO>, RoleDTO, Role>(roleDTOs.ToList(),
            //    _roleRepository,
            //    rdo => rdo.Id,
            //    (r, rdo) =>
            //    {
            //        if (!string.IsNullOrEmpty(rdo.Name))
            //            r.Name = rdo.Name;
            //        if (!string.IsNullOrEmpty(rdo.Description))
            //            r.Remark = rdo.Description;
            //    });
        }

        /// <summary>
        ///     删除角色。
        /// </summary>
        /// <param name="roleIDs">需要删除的角色ID值列表。</param>
        public void DeleteRoles(IList<Guid> roleIDs)
        {
        }

        /// <summary>
        ///     将指定的用户赋予指定的角色。
        /// </summary>
        /// <param name="userId">需要赋予角色的用户ID值。</param>
        /// <param name="roleId">需要向用户赋予的角色ID值。</param>
        public void AssignRole(Guid userId, Guid roleId)
        {
            var user = _userRepository.Get(userId);
            var role = _roleRepository.Get(roleId);
            _domainService.AssignRole(user, role);
        }

        /// <summary>
        ///     将指定的用户从角色中移除。
        /// </summary>
        /// <param name="userId">用户ID值。</param>
        public void UnassignRole(Guid userId)
        {
            var user = _userRepository.Get(userId);
            _domainService.UnassignRole(user);
        }



        /// <summary>
        ///     获取分页数据
        /// </summary> 
        /// <returns></returns>
        public PagedResult<UserDTO> GetUsersPaged(PagingFeature pf, Guid? userGroupId)
        {
            Expression<Func<User, bool>> predicate = x => true;
            if (userGroupId != null)
            {
                predicate = predicate.And(x => x.UserGroups.Any(u => u.Id == userGroupId));
            }
            var paged = _userRepository.Pagging(pf, predicate);

            return paged.To<User, UserDTO>();
        }

        /// <summary>
        ///     获取用户权限
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        public IEnumerable<PermissionDTO> GetPermissionByUserName(string username)
        {
            if (username.IsNullOrEmpty())
            {
                throw new NullReferenceException("参数username不能为空。");
            }

            return _domainService.GetPermissionByUserName(username).To<Permission, PermissionDTO>();
        }

        public IEnumerable<PermissionDTO> GetPermissionByGroupId(Guid groupId)
        {
            if (groupId.IsEmpty())
            {
                throw new NullReferenceException("参数groupId不能为空。");
            }
            return _userGroupRepository.GetPermissionByGroupId(groupId).To<Permission, PermissionDTO>();
        }

        public bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
            string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     全部权限
        /// </summary>
        /// <returns></returns>
        public IEnumerable<PermissionDTO> AllPermissions()
        {
            return _permissionRepository.GetList().To<Permission, PermissionDTO>();
        }

        /// <summary>
        ///     保存权限
        /// </summary>
        /// <param name="ids">被勾选的权限列表</param>
        /// <param name="owner">所有者</param>
        /// <param name="ownerId">所有者id</param>
        /// <remarks>通过所有者来判断具体是给用户或者用户组进行权限配置</remarks>
        /// <returns></returns>
        public Result SavePermission(IList<Guid> ids, string owner, Guid ownerId)
        {
            return _domainService.SavePermission(ids, owner, ownerId);
        }


        /// <summary>
        ///     获取用户权限
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        public IEnumerable<PermissionDTO> GetPermissionById(Guid uid)
        {
            if (uid.IsEmpty())
            {
                throw new NullReferenceException("参数id不能为空。");
            }
            return _domainService.GetPermissionById(uid).To<Permission, PermissionDTO>();
        }

        public bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 检查用户组名称是否被占用
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool CheckUserGroupName(string name)
        {
            name = name.Trim();
            return _userGroupRepository.Exists(x => x.Title == name);
        }

        /// <summary>
        /// 保存用户日志
        /// </summary>
        /// <param name="log"></param>
        public void SaveLog(string log)
        {
            var userLog = log.FromJson<UserLog>();
            userLog.Eventtime = DateTime.Now;
            
            _userLogRepository.Add(userLog);

            Context.Commit();
        }


        public UserLogDTO GetUserLogInfo(Guid id)
        {
            var model = _userLogRepository.Get(id);

            return model.To<UserLogDTO>();
        }

        public Result DeleteUserLogs(Guid[] ids)
        {
            Result res = new Result();
            if (ids.IsEmpty())
            {
                res.Err = "id不能为空";
                return res;
            }
            _userLogRepository.Remove(ids);
            Context.Commit();

            return res;
        }

        public PagedResult<UserLogDTO> GetUserLogPaged(PagingFeature pf)
        {
            var paged = _userLogRepository.Pagging(pf);

            var output = paged.To<UserLog, UserLogDTO>();


            return output;
        }

        /// <summary>
        /// 更新权限库
        /// </summary>
        /// <param name="dtos"></param>
        /// <returns></returns>
        public Result UpdatePermission(IList<PermissionDTO> dtos)
        {
            var allList = _permissionRepository.GetList().OrderByDescending(x => x.Route);
            dtos.ToList().ForEach(x =>
            {
                Guid id = Guid.Parse(x.Code.IsNullOrEmpty() ? x.Route.Md5() : x.Code.Md5());
                if (!_permissionRepository.Exists(y => y.Id == id))
                {
                    x.Id = id;

                    var parents = allList.Where(c => c.Category == "01" && x.Route.StartsWith(c.Route) && c.Route.Length > 0);
                    if (parents.Count() == 1)
                    {
                        x.ParentId = parents.First().Id;
                    }
                    else
                    {
                        x.ParentId = parents.Last().Id;
                        //#if DEBUG
                        //                        throw new Exception("可能有bug。");
                        //#endif
                    }

                    _permissionRepository.Add(x.To<Permission>());
                }
                else
                {
                    var p = _permissionRepository.Get(id);
                    p.Code = x.Code;
                    p.Route = x.Route;
                    p.Title = x.Title;
                    _permissionRepository.Update(p);
                }
            });

            //TODO:删除垃圾权限数据


            _permissionRepository.Context.Commit();
            return new Result();
        }

    }
}